//cLevel.cpp
#include "cLevel.h"

/* Default constructor.
 */
Level::Level()
{
	this->_Create(NULL, 0xFFFF);
}

/* Constructor with file to open.
 */
Level::Level(ROMFile *File)
{
	this->_Create(File, 0xFFFF);
}

/* Constructor with file to open and level number to load.
 */
Level::Level(ROMFile *File, u16 Num)
{
	this->_Create(File, Num);
}

/* PRIVATE: Internal constructor routine.
 * Inputs:
 * -File: File to open.
 * -Num: Level number to load (0xFFFF = none).
 */
void Level::_Create(ROMFile *File, u16 Num)
{
	this->UseFile(File);
	if(File && (Num != 0xFFFF) && this->Load(Num)) this->LevelNum = Num;
	else this->LevelNum = 0xFFFF;
}

/* Destructor.
 */
Level::~Level()
{
}

/* Assigns a ROMFile to read from.
 * Inputs:
 * -File: File to use.
 */
void Level::UseFile(ROMFile *File)
{
	this->File = File;
}

/* Loads a level by number.
 * Inputs:
 * -Num: Level to load.
 * Returns: true on success, false on failure.
 */
bool Level::Load(u16 Num)
{
	SNESPointer Ptr;
	SMWObject Obj;
	u32 Screen = 0, ObjCount = 0;
	u8 Byte[5];
	u32 NumObjBytes = 0;
	
	if(!this->File)
	{
		DebugOut(DO_MINOR, "No file loaded.\n");
		return false;
	}
	
	this->Unload();
	Ptr.Read(this->File, 0x2E200 + ((u32)Num * 3));
	DebugOut(DO_ALL, "Load level 0x%03X layer 1 from %06X (SNES %06X)\n", Num,
		Ptr.ToFileAddr(), Ptr.ToSNESAddr());
	
	if(!this->File->Read(Byte, 5, &Ptr))
	{
		DebugOut(DO_MAJOR, "Failed to read header.\n");
		return false;
	}
	
	//We're not using the Header.Byte field here because I haven't figured out
	//how to disable the compiler's alignment/padding in a way that will work on
	//more than one compiler. The padding makes the fields not line up.
	this->Header.BGPal =			BITS(Byte[0], 5, 7);
	this->Header.NumScreens =		BITS(Byte[0], 0, 4) + 1; //this is one less than the real value
	this->Header.BGCol =			BITS(Byte[1], 5, 7);
	this->Header.Mode =				BITS(Byte[1], 0, 4);
	this->Header.Layer3Priority =	BITS(Byte[2], 7, 7);
	this->Header.Music =			BITS(Byte[2], 4, 6);
	this->Header.Spriteset =		BITS(Byte[2], 0, 3);
	this->Header.Time =				BITS(Byte[3], 6, 7);
	this->Header.SprPal =			BITS(Byte[3], 3, 5);
	this->Header.FGPal =			BITS(Byte[3], 0, 2);
	this->Header.ItemMem =			BITS(Byte[4], 6, 7);
	this->Header.VScroll =			BITS(Byte[4], 4, 5);
	this->Header.Tileset = 			BITS(Byte[4], 0, 3);
	
	DebugOut(DO_ALL, "Header: %02X %02X %02X %02X %02X\n", Byte[0], Byte[1],
		Byte[2], Byte[3], Byte[4]);
	DebugOut(DO_ALL,
		"BGPal=%d		NumScreens=%d	BGCol=%d		Mode=%d\n"
		"Layer3=%d	Music=%d		SprSet=%d	Time=%d\n"
		"SprPal=%d	FGPal=%d		ItemMem=%d	VScroll=%d\t"
		"Tileset=%d\n",
		this->Header.BGPal, this->Header.NumScreens, this->Header.BGCol,
		this->Header.Mode, this->Header.Layer3Priority, this->Header.Music,
		this->Header.Spriteset, this->Header.Time, this->Header.SprPal,
		this->Header.FGPal, this->Header.ItemMem, this->Header.VScroll,
		this->Header.Tileset);
		
	DebugOut(DO_STATUS, "Reading layer 1... ");
	while(Obj.Read(this, this->File, &Screen))
	{
		if(Obj.Type == SMWObject::OBJ_SCREEN_EXIT)
		{
			this->ScreenExit[Obj.YPos] = Obj.ScreenExitDest;
			//TODO: only do this if the hack to set the high bit is not installed
			this->ScreenExit[Obj.YPos] |= (this->LevelNum & 0x100);
		}
		else if(Obj.Type == SMWObject::OBJ_SCREEN_JUMP); //do nothing; Obj.Read
			//has already set the screen number
		else this->Layer1Obj.push_back(Obj);
		ObjCount++;
		NumObjBytes += Obj.NumBytes;
	}
	
	DebugOut(DO_STATUS, "Found %u objects, occupying %u bytes.\n", ObjCount,
		NumObjBytes);
		
	//TODO: read layer 2
		
	//Load Map16
	for(u32 i=0; i<16*27*32; i++) this->Map16[i] = EMPTY_BLOCK;
	this->ReadMap16();
	
	//Decode objects
	DebugOut(DO_STATUS, "Decoding objects... ");
	for(std::list<SMWObject>::iterator i = this->Layer1Obj.begin();
		i != this->Layer1Obj.end(); i++) i->Decode(this, false);
	for(std::list<SMWObject>::iterator i = this->Layer2Obj.begin();
		i != this->Layer2Obj.end(); i++) i->Decode(this, true);
	DebugOut(DO_STATUS, "Done.\nReading palettes... ");
		
	//Read palettes
	for(u32 i=0; i<16; i++)
	{
		for(u32 j=0; j<16; j++) this->Palette[i][j] = 0;
	}
	this->LoadSharedPalettes();
	this->LoadObjPalettes();
	this->LoadSpritePalettes();
	this->LoadBGPalettes();
	this->LoadAnimatedPalettes();
	this->LoadBGColour();
	DebugOut(DO_STATUS, "Done.\nReading graphics...\n");
	
	//Read graphics
	//TEST
	//DebugOut(DO_ALL, "Decompressed %u tiles\n",
	//	this->GFX.LoadFromROM(this->File, 0x40200, 744, COMP_LZ2)); //Mario
	//this->GFX.LoadFromFile("Graphics/GFX14.bin", 0, 128, 0, COMP_NONE);
	//this->GFX.LoadFromFile("Graphics/GFX17.bin", 0, 128, 128, COMP_NONE);
	//this->GFX.LoadFromFile("Graphics/GFX1B.bin", 0, 128, 256, COMP_NONE);
	//this->GFX.LoadFromFile("Graphics/GFX15.bin", 0, 128, 384, COMP_NONE);
	this->LoadGraphics();
	
	DebugOut(DO_STATUS, "Level loaded successfully.\n");
	this->LevelNum = Num;
	
	return true;
}

/* Loads the graphics files for this level.
 */
void Level::LoadGraphics()
{
	//Object graphics
	for(u32 i=0; i<4; i++)
	{
		this->LoadGraphicsFile(this->File->Read(0x2B2B +
			(this->Header.Tileset * 4) + i), 128 * i);
	}
	
	//Sprite graphics
	for(u32 i=0; i<4; i++)
	{
		this->LoadGraphicsFile(this->File->Read(0x2AC3 +
			(this->Header.Spriteset * 4) + i), 128 * (i + 4));
	}
	
	//Animated graphics
	this->AnimatedGFX.LoadFromROM(this->File, 0x441C0, 384, 0,
		COMP_3BPP_LZ2);
	
	this->DrawAnimationFrame(MAX_INT); //Copy non-animated graphics
	this->DrawAnimationFrame(0);
}

/* Copies animated graphics tiles for the specified animation frame.
 * Inputs:
 * -Frame: Frame number. Use MAX_INT to copy the graphics that are not animated
 *  but are still stored in the animated graphics file.
 */
void Level::DrawAnimationFrame(u32 Frame)
{
	u32 F16 = (Frame & 3) * 16, F4 = (Frame & 1) * 4;
	
	//save CPU power by only copying static tiles once
	if(Frame == MAX_INT)
	{
		//Palettes
		for(u32 P=0; P<16; P++)
		{
			for(u32 C=0; C<16; C++)
			{
				if(this->AnimPalette[0][P][C])
					this->Palette[P][C] = this->AnimPalette[0][P][C];
			}
		}
		
		//Tiles - TODO: there must be a table for this
		this->AnimatedGFX.CopyTiles(0x0C0, &this->GFX, 0x40, 4); //static ? block
		this->AnimatedGFX.CopyTiles(0x0C0, &this->GFX, 0x48, 4); //static ? block
		this->AnimatedGFX.CopyTiles(0x14C, &this->GFX, 0x4C, 4); //garbage?*
		this->AnimatedGFX.CopyTiles(0x0A4, &this->GFX, 0x50, 4); //door
		this->AnimatedGFX.CopyTiles(0x0B4, &this->GFX, 0x58, 4); //used block
		this->AnimatedGFX.CopyTiles(0x0A4, &this->GFX, 0x85, 2); //door top
		this->AnimatedGFX.CopyTiles(0x0A6, &this->GFX, 0x95, 2); //door bottom
		this->AnimatedGFX.CopyTiles(0x0A0, &this->GFX, 0xDA, 4); //on/off switch
		//*supposed to animate but I'm not sure where the 4th frame comes from
		return;
	}
	
	//Palettes
	for(u32 P=0; P<16; P++)
	{
		for(u32 C=0; C<16; C++)
		{
			if(this->AnimPalette[Frame & 3][P][C])
				this->Palette[P][C] = this->AnimPalette[Frame & 3][P][C];
		}
	}
	
	//Tiles	
	this->AnimatedGFX.CopyTiles(0x088 + F16, &this->GFX, 0x44, 4); //seaweed
	this->AnimatedGFX.CopyTiles(0x0CC + F16, &this->GFX, 0x54, 4); //coin
	this->AnimatedGFX.CopyTiles(0x138 + F4,  &this->GFX, 0x5C, 4); //muncher
	this->AnimatedGFX.CopyTiles(0x0C0 + F16, &this->GFX, 0x60, 8); //? block
	this->AnimatedGFX.CopyTiles(0x0CC + F16, &this->GFX, 0x6C, 4); //coin
	this->AnimatedGFX.CopyTiles(0x100 + F16, &this->GFX, 0x70, 8); //water
	this->AnimatedGFX.CopyTiles(0x0C8 + F16, &this->GFX, 0xEA, 4); //turn block
	
	//Presumably the duplicate graphics are used so that one object can switch
	//to them an animate without affecting others (e.g. other doors in the room
	//won't also open). Similarly the non-animated blocks are here so that
	//objects can switch to them when POW is active to avoid being animated.
	//This is all just a guess though.
}

/* Calculates the location of a graphics file by ID.
 * Inputs:
 * -ID: File ID.
 * Returns: Address.
 */
SNESPointer Level::GetGraphicsFileAddr(u8 ID)
{
	SNESPointer P;
	u8 Byte[3];
	
	//whoever wrote the wiki article made a typo in this first address.
	//it's B992, not B922.
	Byte[0] = this->File->Read(0x3B92 + ID);
	Byte[1] = this->File->Read(0x3BC4 + ID);
	Byte[2] = this->File->Read(0x3BF6 + ID);
	P.SetSNESAddr(Byte[2], (Byte[1] << 8) | Byte[0]);
	//DebugOut(DO_ALL, "GFX%02X at %02X:%02X%02X = %06X\n", ID, Byte[2], Byte[1],
	//	Byte[0], P.ToFileAddr());
	return P;
}

/* Loads a graphics file.
 * Inputs:
 * -ID: File ID.
 * -Tile: Tile number to load to.
 * Notes:
 * -GFX32 and GFX33 are not in the pointer table.
 */
void Level::LoadGraphicsFile(u8 ID, u32 Tile)
{
	SNESPointer P = this->GetGraphicsFileAddr(ID);
	u32 NumLoaded;
	
	DebugOut(DO_ALL, "Loading GFX%02X... ", ID);
	NumLoaded = this->GFX.LoadFromROM(this->File, P.ToFileAddr(), 128,
		Tile, COMP_3BPP_LZ2);
	if(NumLoaded < 128) DebugOut(DO_MINOR,
		"Only %u tiles loaded from GFX%02X\n", NumLoaded, ID);
}

/* Loads the shared/hardcoded palettes.
 */
void Level::LoadSharedPalettes()
{
	//Shared object palettes
	//I don't know why the "colour ID" as shown on the wiki is 0x84, that would
	//seem to suggest it loads to column 8, when in fact it loads to column 2.
	//It looks as though the column IDs are 6 greater or less than expected.
	this->File->Seek(0x3450);
	for(u32 P = 4; P < 14; P++)
	{
		for(u32 C = 2; C < 8; C++)
			this->Palette[P][C] = this->File->Read() | (this->File->Read() << 8);
	}
	
	//Berry objects
	this->File->Seek(0x3874);
	for(u32 P = 2; P < 5; P++)
	{
		for(u32 C = 9; C < 0x10; C++)
			this->Palette[P][C] = this->File->Read() | (this->File->Read() << 8);
	}
	
	//Berry sprites
	this->File->Seek(0x3874);
	for(u32 P = 9; P < 0xC; P++)
	{
		for(u32 C = 9; C < 0x10; C++)
			this->Palette[P][C] = this->File->Read() | (this->File->Read() << 8);
	}
	
	//Layer 3
	this->File->Seek(0x3370);
	for(u32 P = 0; P < 2; P++)
	{
		for(u32 C = 8; C < 0x10; C++)
			this->Palette[P][C] = this->File->Read() | (this->File->Read() << 8);
	}
	
	//Mario
	this->File->Seek(0x34C8);
	for(u32 C = 6; C < 0x10; C++)
		this->Palette[8][C] = this->File->Read() | (this->File->Read() << 8);
	
	
	//Hardcoded black and white
	/* TODO: read the colours themselves from ROM. Also, is the black actually
	 * hardcoded? It's not terribly important because it's transparent, but a
	 * hack such as PalASM might use it. */
	for(u32 P = 0; P < 16; P++)
	{
		this->Palette[P][0] = 0;
		this->Palette[P][1] = (P < 8) ? 0x7FDD : 0x7FFF;
	}
}

/* Wrapper for loading a palette set.
 * Inputs:
 * -Idx: Palette set.
 * -Base: Base address. (SNES address.)
 * -PStart, PEnd: First and last palette #.
 * -CStart, CEnd: First and last colour #.
 */
void Level::LoadPartialPalette(u32 Idx, u32 Base, u32 PStart, u32 PEnd,
u32 CStart, u32 CEnd)
{
	SNESPointer P(0, 0xABD3 + Idx);
	this->File->Seek(&P);
	
	P.SetSNESAddr(0, Base + this->File->Read());
	this->File->Seek(&P);
	
	for(u32 P = PStart; P <= PEnd; P++)
	{
		for(u32 C = CStart; C <= CEnd; C++)
			this->Palette[P][C] = this->File->Read() | (this->File->Read() << 8);
	}
}

/* Loads the object palettes for this colour set.
 */
void Level::LoadObjPalettes()
{
	this->LoadPartialPalette(this->Header.FGPal, 0xB190, 2, 3, 2, 7);
}

/* Loads the sprite palettes for this colour set.
 */
void Level::LoadSpritePalettes()
{
	this->LoadPartialPalette(this->Header.SprPal, 0xB318, 14, 15, 2, 7);
}

/* Loads the background palettes for this colour set.
 */
void Level::LoadBGPalettes()
{
	this->LoadPartialPalette(this->Header.BGPal, 0xB0B0, 0, 1, 2, 7);
}

/* Loads animated palettes.
 */
void Level::LoadAnimatedPalettes()
{
	for(u32 F=0; F<16; F++)
	{
		for(u32 P=0; P<16; P++)
		{
			for(u32 C=0; C<16; C++)
				this->AnimPalette[F][P][C] = 0;
		}
	}
	
	//Animated coin colour
	this->File->Seek(0x380C);
	for(u32 F=0; F<16; F++)
	{
		this->AnimPalette[F][6][4] =
			this->File->Read() | (this->File->Read() << 8);
	}
	
	//for(u32 F=8; F<16; F++)
	//	this->AnimPalette[F][6][4] = this->AnimPalette[F - 8][6][4];
}

/* Loads the background colour.
 */
void Level::LoadBGColour()
{
	this->File->Seek(0x32A0 + (this->Header.BGCol * 2));
	this->BGColour = this->File->Read() | (this->File->Read() << 8);
}

/* Reads Map16 data for this tileset.
 * Returns: true on success, false on failure.
 */
bool Level::ReadMap16()
{
	//u32 TotalRead = 0;
	//u32 TotalSize = sizeof(this->Map16Tile) + sizeof(this->BGMap16Tile);
	SNESPointer TilesetData, TilePtr;
	u16 BlockPtr[512];
	
	//Init the block data pointers
	//Todo: in some cases it uses 0x9100 instead of 0xD000 - when?
	for(u32 i=0; i<512; i++) BlockPtr[i] = 0xD000 + (i * 8);
	
	
	//----------------------
	//Decompiled from 05:81FB.
	
	TilePtr.SetSNESAddr(5, 0x8000 + (this->Header.Tileset * 2));
	this->File->Seek(&TilePtr);
	
	TilePtr.SetSNESAddr(5, 0x81BB);
	u32 Idx = 0, Count;
	u32 Ptr1 = this->File->Read() | (this->File->Read() << 8);
	u32 Ptr2 = 0x8000;
	
	for(u32 i=0; i<0x40; i++)
	{
		Count = this->File->Read(TilePtr.ToFileAddr() + i);
		for(u32 j=0; j<8; j++)
		{
			Count <<= 1;
			if(Count & 0x100)
			{
				BlockPtr[Idx] = Ptr2;
				Ptr2 += 8;
			}
			else
			{
				BlockPtr[Idx] = Ptr1;
				Ptr1 += 8;
			}
			Idx++;
			if(Idx > 512)
			{
				DebugOut(DO_MAJOR, "WTF\n");
				break;
			}
		}
		if(Idx > 512) break;
	}
	
	if((this->Header.Tileset == 0) || (this->Header.Tileset == 7))
	{
		Idx = 0x1C4;
		Ptr1 = 0x8A70;
		for(s32 X=3; X>=0; X--)
		{
			BlockPtr[Idx] = Ptr1;
			Ptr1 += 8;
			Idx++;
		}

		Idx = 0x1EC;
		for(s32 X=3; X>=0; X--)
		{
			BlockPtr[Idx] = Ptr1;
			Ptr1 += 8;
			Idx++;
		}
	}
	
	
	//----------------------
	//End decompiled routine.
	
	//Read the block data
	for(u32 i=0; i<512; i++)
	{
		TilePtr.SetSNESAddr(0xD, BlockPtr[i]);
		this->File->Read((u8*)&this->Map16Tile[i * 4], 8, &TilePtr);
	}
	
	//Set pipe tiles - we'll just use set 0 for now
	//0x28976 + ((pipe set * 2) & 6)
	TilePtr.Read2Byte(this->File, 0x28976, 0xD);
	for(u32 i=0; i<8; i++)
	{
		BlockPtr[i + 0x133] = TilePtr.ToFileAddr();
		TilePtr += 8;
	}
	
	return true;
	
	/*TilesetData.Read2Byte(this->File, 0x28200 + (this->Header.Tileset * 2), 13);
	
	//Todo: there must be tables of this
	TotalRead =
		this->File->Read((u8*)this->Map16Tile, 0x380, 0x68200)
	  + this->File->Read((u8*)&this->Map16Tile[0x400], 0x380, 0x68598)
	  + this->File->Read((u8*)&this->Map16Tile[0x1C0], 0x380, 0x68918)
	  + this->File->Read((u8*)&this->Map16Tile[0x1CC], 0x468, &TilesetData);
	TilesetData += 0x468;
	TotalRead +=
	    this->File->Read((u8*)&this->Map16Tile[0x41C], 0x468, &TilesetData)
	  + this->File->Read((u8*)&this->Map16Tile[0x444], 0x770, 0x685D0)
	  + this->File->Read((u8*)this->BGMap16Tile, sizeof(this->BGMap16Tile), 0x69300);
	  */
	//this->File->Read((u8*)this->Map16Tile, 0x800, 0x68D30);
	//if(TotalRead < TotalSize)
	//{
		//this isn't properly implemented yet so don't go spouting nonsense
		//DebugOut(DO_MAJOR,
		//	"Not all Map16 data was read. ROM is corrupt or inaccessible.\n");
	//	return false;
	//}
	//return true;
}

/* Renders the level to a DrawBox.
 * Inputs:
 * -Buf: Buffer to render to.
 * -ScrollX, ScrollY: Block coordinates of upper-left block to render.
 */
void Level::Render(ImgBuf *Buf, u32 ScrollX, u32 ScrollY)
{
	u32 LevelWidth = MAX_SCREENS * 16, Offs, Tile;
	//char Buf[32];
	
	//todo: vertical level support
	Buf->Clear(
		BITS(this->BGColour, 0, 4) << 3,
		BITS(this->BGColour, 5, 9) << 3,
		BITS(this->BGColour, 10, 14) << 3, 255);
	for(u32 Y = 0; Y < 27; Y++)
	{
		for(u32 X = 0; X < LevelWidth; X++)
		{
			Offs = ((Y + ScrollY) * LevelWidth) + (X + ScrollX);
			if(this->Map16[Offs] == EMPTY_BLOCK) continue;
			
			Tile = this->Map16[Offs] * 4;
			this->GFX.RenderRawTile(this->Map16Tile[Tile],
				(u16*)this->Palette, Buf, X*16, Y*16, true);
			this->GFX.RenderRawTile(this->Map16Tile[Tile+1],
				(u16*)this->Palette, Buf, X*16, (Y*16)+8, true);
			this->GFX.RenderRawTile(this->Map16Tile[Tile+2],
				(u16*)this->Palette, Buf, (X*16)+8, Y*16, true);
			this->GFX.RenderRawTile(this->Map16Tile[Tile+3],
				(u16*)this->Palette, Buf, (X*16)+8, (Y*16)+8, true);
			
			//Render boxes instead of graphics
			//Box->SetFGColour((this->Map16[Offs] & 0x100) ? 255 : 0,
			//	0x80 | (this->Map16[Offs] & 0xF0),
			//	0x80 | ((this->Map16[Offs] & 0xF) << 4));
			//Box->DrawRectangle(X * 16, Y * 16, 16, 16, true);
			
			//Debug: number Map16 tiles
			//Box->SetFGColour(0, 0, 0);
			//sprintf(Buf, "%02X", this->Map16[Offs] & 0xFF);
			//Box->DrawText((X * 16) + 1, (Y * 16) + 1, Buf);
		}
	}
	
	//Debug: outline objects
	/*for(std::list<SMWObject>::iterator i = this->Layer1Obj.begin();
	i != this->Layer1Obj.end(); i++)
	{
		if(!i->IsVisible()) continue;
		Buf->SetFGColour(255, 0, 0);
		Buf->DrawRectangle(((i->XPos - ScrollX) * 16) + 1,
			((i->YPos - ScrollY) * 16) + 1,
			(i->Width * 16) - 2, (i->Height * 16) - 2, false);
		
		//Box->SetFGColour(0, 0, 0);
		//sprintf(Buf, "%02X", i->ObjID);
		//Box->DrawText(((i->XPos - ScrollX) * 16) + 1,
		//	((i->YPos - ScrollY) * 16) + 1, Buf);
	}*/
}

/* Retrieves the current level number.
 */
u16 Level::GetNum()
{
	return this->LevelNum;
}

/* Sets the Map16 tile at the specified location. Used by object decoding.
 * Inputs:
 * -X, Y: Block coordinates.
 * -Tile: Tile number.
 * Notes: This emulates the tile wrapping when an object extends outside of the
 * level.
 */
void Level::SetTileAt(u32 X, u32 Y, u16 Tile)
{
	u32 Offs;
	if(Y > 26) Offs = ((Y - 26) * 32 * 16) + X + 16;
	else Offs = (Y * 32 * 16) + X;
	
	if(Offs < 16*27*32) this->Map16[Offs] = Tile;
}

/* Retrieves the Map16 tile at the specified location.
 * Inputs:
 * -X, Y: Block coordinates.
 * Returns: Tile number.
 * Notes: This does NOT emulate tile wrapping, and returns 0xFFFF for any
 * coordinates outside of the level.
 */
u16 Level::GetTileAt(u32 X, u32 Y)
{
	u32 Offs = (Y * 32 * 16) + X;
	if(Offs < 16*27*32) return this->Map16[Offs]; else return 0xFFFF;
}

/* Retrieves the object at the specified location.
 * Inputs:
 * -X, Y: Block coordinates.
 * Returns: Pointer to object, or NULL if there is no object at that location.
 */
SMWObject* Level::GetObjectAt(u32 X, u32 Y)
{
	//todo: this might have to ask the object itself whether it intersects,
	//because of slopes and other such things that don't fill their entire
	//rectangle
	std::list<SMWObject>::iterator i = this->Layer1Obj.end();
	do {
		i--;
		if((i->XPos <= X) && ((i->XPos + i->Width) > X)
		&& (i->YPos <= Y) && ((i->YPos + i->Height) > Y)) return &(*i);
	} while(i != this->Layer1Obj.begin());
	
	//TODO: check layer 2
	return NULL;
}

/* Retrieves a colour of the palette.
 * Inputs:
 * -Palette: Palette number to read.
 * -Colour: Which colour of the palette to read.
 * Returns: SNES colour value.
 */
u16 Level::GetColour(u8 Palette, u8 Colour)
{
	return this->Palette[Palette][Colour];
}

/* Retrieves the background colour.
 */
u16 Level::GetBGColour()
{
	return this->BGColour;
}

/* Unloads the level.
 * Notes:
 * -Called automatically before loading another level.
 */
void Level::Unload()
{
	this->Layer1Obj.clear();
	this->Layer2Obj.clear();
	memset(this->ScreenExit, 0, sizeof(this->ScreenExit));
	memset(&this->Header, 0, sizeof(this->Header));
	this->LevelNum = 0xFFFF;
}
